package com.jacky.iot.resources;

import org.eclipse.californium.core.CoapResource;
import org.eclipse.californium.core.coap.CoAP;
import org.eclipse.californium.core.coap.MediaTypeRegistry;
import org.eclipse.californium.core.coap.Request;
import org.eclipse.californium.core.coap.Response;
import org.eclipse.californium.core.server.resources.CoapExchange;

import java.nio.ByteBuffer;
import java.util.Arrays;

import static org.eclipse.californium.core.coap.MediaTypeRegistry.UNDEFINED;

public class ValidateResource extends CoapResource {

    private final static byte[] EMPTY_ETAG = {0};

    private byte[] data = null;
    private int dataCf = MediaTypeRegistry.TEXT_PLAIN;
    private byte[] eTag = EMPTY_ETAG;

    public ValidateResource(String name) {
        super(name);
        getAttributes().setTitle("Resource which varies");
    }

    @Override
    public void handleGET(CoapExchange exchange) {

        // 获取请求
        Request request = exchange.advanced().getRequest();
        // 请求响应
        Response response;

        if (exchange.getRequestOptions().containsETag(eTag)) {
            response = new Response(CoAP.ResponseCode.VALID);
            response.getOptions().addETag(eTag);

            storeData(null, UNDEFINED);
        } else {
            response = new Response(CoAP.ResponseCode.CONTENT);
            if (data == null) {
                StringBuilder payload = new StringBuilder();
                payload.append(String.format("Type: %d (%s)\nCode: %d (%s)\nMID: %d",
                        request.getType().value, request.getType(), request.getCode().value, request.getCode(), request.getMID()));

                if (!request.hasEmptyToken()) {
                    payload.append("\nToken: ");
                    payload.append(request.getTokenString());
                }
                if (payload.length() > 64) {
                    payload.delete(63, payload.length());
                    payload.append('》');
                }
                response.setPayload(payload.toString());
                response.getOptions().setContentFormat(MediaTypeRegistry.TEXT_PLAIN);
            } else {
                response.setPayload(data);
                response.getOptions().setContentFormat(dataCf);
            }
            response.getOptions().addETag(eTag);
        }
        exchange.respond(response);
    }

    @Override
    public void handlePUT(CoapExchange exchange) {
        if (exchange.getRequestOptions().isIfMatch(eTag)) {
            if (exchange.getRequestOptions().hasContentFormat()) {
                storeData(exchange.getRequestPayload(), exchange.getRequestOptions().getContentFormat());
                exchange.setETag(eTag);
                exchange.respond(CoAP.ResponseCode.CHANGED);
            } else {
                exchange.respond(CoAP.ResponseCode.BAD_REQUEST, "Content-Format not set");
            }
        } else if (exchange.getRequestOptions().hasIfNoneMatch() && data == null) {
            storeData(exchange.getRequestPayload(), exchange.getRequestOptions().getContentFormat());
            exchange.respond(CoAP.ResponseCode.CREATED);
        } else {
            exchange.respond(CoAP.ResponseCode.PRECONDITION_FAILED);
            storeData(null, MediaTypeRegistry.UNDEFINED);
        }
    }

    @Override
    public void handleDELETE(CoapExchange exchange) {
        storeData(null, MediaTypeRegistry.UNDEFINED);
        exchange.respond(CoAP.ResponseCode.DELETED);
    }

    private synchronized void storeData(byte[] payload, int cf) {
        if (payload != null) {
            data = payload;
            dataCf = cf;

            eTag = ByteBuffer.allocate(4).putInt(Arrays.hashCode(data)).array();

            // 设置负载及内容类型
            getAttributes().clearContentType();
            getAttributes().addContentType(dataCf);
            getAttributes().setMaximumSizeEstimate(data.length);
        } else {
            data = null;
            eTag = EMPTY_ETAG;
        }

        // 通知资源状态已改变
        changed();
    }
}
